package com.smile.frame.common.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelUtil;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.smile.frame.common.annotation.HeaderName;
import com.smile.frame.common.exception.BaseErrorCodeEnum;
import com.smile.frame.common.exception.BizException;


import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * hutool 导出excel 工具类
 *
 * @author LGC
 * @date 2021/8/28 14:09

 */
public class HuToolExcelUtil {

    public static void commonExcelExport(HttpServletResponse response, List<Map<String, Object>> dataList, String fileName) {
        BigExcelWriter writer = (BigExcelWriter) ExcelUtil.getBigWriter();
        ServletOutputStream out = null;
        try {
            writer.write(dataList, true);
//            // 设置请求头属性
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            out = response.getOutputStream();
            writer.flush(out, true);
        } catch (IOException e) {
            throw new BizException(BaseErrorCodeEnum.BASE_EXCEL_EXPORT_ERROR);
        } finally {
            writer.close();
            IoUtil.close(writer);
        }
    }

    /**
     * 实体转 map, 自定义字段导出
     *
     * @param entity
     * @param names  指定列
     * @param <O>
     * @return
     * @throws Exception
     */
    public static <O> Map<String, Object> entityToMap(O entity, List<String> names) throws Exception {
        Map<String, Object> resMap = new LinkedHashMap<>();
        Class<?> clazz = entity.getClass();
        // 获取 实体类 中所有的字段
        Field[] declaredFields = clazz.getDeclaredFields();

        List<Field> collect = Arrays.stream(declaredFields).sorted((o1, o2) -> {
            HeaderName a = o1.getAnnotation(HeaderName.class);
            HeaderName b = o2.getAnnotation(HeaderName.class);
            if (a != null && b != null) {
                int aa = a.sort();
                int bb = b.sort();
                return aa - bb;
            }
            return 0;
        }).collect(Collectors.toList());
        for (Field declaredField : collect) {
            // 这里设置为 true 才可以访问到 实体类中的 private 字段
            declaredField.setAccessible(true);
            // 获取字段所对应的注解
            HeaderName annotation = declaredField.getAnnotation(HeaderName.class);
            if (null != annotation) {
                JsonFormat JsonFormat = declaredField.getAnnotation(JsonFormat.class);
                // 有注解 则 获取 注解的值（表头名称）
                String value = annotation.value();
                // 再判断 实体类中是否有这个表头
                if (CollectionUtil.isNotEmpty(names) && names.contains(value)) {
                    if (JsonFormat != null && StrUtil.isNotBlank(JsonFormat.pattern())) {
                        resMap.put(value, DateUtil.format((Date) declaredField.get(entity), JsonFormat.pattern()));
                    } else {
                        resMap.put(value, declaredField.get(entity) != null ? String.valueOf(declaredField.get(entity)) : "");
                    }
                } else {
                    if (JsonFormat != null && StrUtil.isNotBlank(JsonFormat.pattern())) {
                        resMap.put(value, DateUtil.format((Date) declaredField.get(entity), JsonFormat.pattern()));
                    } else {
                        resMap.put(value, declaredField.get(entity) != null ? String.valueOf(declaredField.get(entity)) : "");
                    }
                }
            }
        }
        return resMap;
    }

}
